package cloud.ipanda.base;

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import org.apache.poi.xwpf.usermodel.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * word 导出工具类
 */
public class WordUtilsBack {

    /**
     * 用于判断导出的word是否转pdf
     */
    public static int judgment = 0;

    public WordUtilsBack() {
        judgment = 0;
    }


    /**
     * 根据模板生成word
     *
     * @param path      模板的路径
     * @param params    需要替换的参数
     * @param tableList 需要插入的参数
     * @param fileName  生成word文件的文件名
     */
    public void getWord(String path, Map<String, Object> params, List<String[]> tableList, String fileName) throws Exception {
        String saveRoute = path.substring(0, path.indexOf("\\"));

        File file = new File(path);
        InputStream is = new FileInputStream(file);
        CustomXWPFDocument doc = new CustomXWPFDocument(is);

        this.replaceInPara(doc, params); // 替换文本里面的变量
        this.replaceInTable(doc, params, tableList); // 替换表格里面的变量
        OutputStream os = null;
        if (judgment == 0) {
            fileName = java.net.URLDecoder.decode(fileName, "UTF-8");
            os = new FileOutputStream(saveRoute + "\\word\\" + fileName);

            doc.write(os);

            String pdf = fileName.substring(0, fileName.lastIndexOf(".")) + ".pdf"; // 截掉
            wToPdfChange(saveRoute + "\\word\\" + fileName, saveRoute + "\\word\\" + pdf);
        } else {
//			os = response.getOutputStream();
            fileName = java.net.URLDecoder.decode(fileName, "UTF-8");
            os = new FileOutputStream(saveRoute + "\\word\\" + fileName);
            //response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
            doc.write(os);
            judgment = 0;
        }

        this.close(os);
        this.close(is);
    }
    /**
     * 根据模板生成word
     *
     * @param path      模板的路径
     * @param params    需要替换的参数
     * @param tableList 需要插入的参数
     * @param fileName  生成word文件的文件名
     * @param response
     */
    public void getWord(String path, Map<String, Object> params, List<String[]> tableList, String fileName,
                        HttpServletResponse response) throws Exception {
        String saveRoute = path.substring(0, path.indexOf("\\"));

        File file = new File(path);
        InputStream is = new FileInputStream(file);
        CustomXWPFDocument doc = new CustomXWPFDocument(is);

        this.replaceInPara(doc, params); // 替换文本里面的变量
        this.replaceInTable(doc, params, tableList); // 替换表格里面的变量
        OutputStream os = null;
        if (judgment == 0) {
            fileName = java.net.URLDecoder.decode(fileName, "UTF-8");
            os = new FileOutputStream(saveRoute + "\\word\\" + fileName);

            doc.write(os);

            String pdf = fileName.substring(0, fileName.lastIndexOf(".")) + ".pdf"; // 截掉
            wToPdfChange(saveRoute + "\\word\\" + fileName, saveRoute + "\\word\\" + pdf);

            try {
                System.out.println("========================pdf下载开始========================");
                // path是指欲下载的文件的路径。
                file = new File(saveRoute + "\\word\\" + pdf);
                // 取得文件名。
                String filename = URLEncoder.encode(file.getName(), "utf-8");
                // 取得文件的后缀名。
                String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();
                // 以流的形式下载文件。
                is = new BufferedInputStream(new FileInputStream(saveRoute + "\\word\\" + pdf));
                byte[] buffer = new byte[is.available()];
                is.read(buffer);
                // 清空response
                response.reset();
                // 设置response的Header
                response.addHeader("Content-Disposition", "attachment;filename=" + filename);
                response.addHeader("Content-Length", "" + file.length());
                os = new BufferedOutputStream(response.getOutputStream());
                response.setContentType("application/octet-stream");
                os.write(buffer);
                os.flush();
                System.out.println("========================pdf下载结束========================");
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        } else {
//			os = response.getOutputStream();
            fileName = java.net.URLDecoder.decode(fileName, "UTF-8");
            os = new FileOutputStream(saveRoute + "\\word\\" + fileName);
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
            doc.write(os);
            judgment = 0;
        }

        this.close(os);
        this.close(is);
    }

    /**
     * word 转 pdf
     *
     * @param wordFile word 的路径 word 的路径
     * @param pdfFile  pdf 的路径
     */
    public static void wToPdfChange(String wordFile, String pdfFile) {
        ActiveXComponent app = null;
        Dispatch document = null;
        System.out.println("========================开始转换========================");
        try {
            // 打开word
            System.out.println("开始打开word");
            app = new ActiveXComponent("Word.Application");

            // 获得word中所有打开的文档
            Dispatch documents = app.getProperty("Documents").toDispatch();
            System.out.println("打开文件: " + wordFile);
            // 打开文档
            document = Dispatch.call(documents, "Open", wordFile, false, true).toDispatch();
            // 如果文件存在的话，不会覆盖，会直接报错，所以我们需要判断文件是否存在
            File target = new File(pdfFile);
            if (target.exists()) {
                target.delete();
            }
            System.out.println("另存为: " + pdfFile);
            Dispatch.call(document, "SaveAs", pdfFile, 17);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("转换失败" + e.getMessage());
        } finally {
            // 关闭office
//			app.invoke("Quit", 0);

            if (document != null) {
                // 关闭文档
                Dispatch.call(document, "Close", false);
            }
            if (app != null) {
                app.invoke("Quit", 0);
            }

            // 获取系统类型
            String osName = System.getProperty("os.name");
            // 判断是系统类型
            if (osName.toLowerCase().startsWith("win")) {
                System.out.println(osName);
                // window系统
                String killCmd = "taskkill /f /im wps.exe";
                String killCmd1 = "taskkill /f /im wpscenter.exe";
                Process p;
                try {
                    p = Runtime.getRuntime().exec(killCmd);
                    p = Runtime.getRuntime().exec(killCmd1);
                    int runnngStatus = p.waitFor();
                    System.out.println("已杀" + runnngStatus);
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("转换失败" + e.getMessage());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("转换失败" + e.getMessage());
                }
            }
        }
        System.out.println("========================转换结束========================");
    }

    /**
     * 替换段落里面的变量
     *
     * @param doc    要替换的文档
     * @param params 参数
     */
    private void replaceInPara(CustomXWPFDocument doc, Map<String, Object> params) throws IOException {
        Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
        XWPFParagraph para;
        while (iterator.hasNext()) {
            para = iterator.next();
            this.replaceInPara(para, params, doc);
        }
    }

    /**
     * 替换段落里面的变量
     *
     * @param para   要替换的段落
     * @param params 参数
     */
    private void replaceInPara(XWPFParagraph para, Map<String, Object> params, CustomXWPFDocument doc) throws IOException {
        List<XWPFRun> runs;
        Matcher matcher;
        if (this.matcher(para.getParagraphText()).find()) {
            runs = para.getRuns();
            int start = -1;
            int end = -1;
            String runsIndex = "";
            String str = "";
            for (int i = 0; i < runs.size(); i++) {
                XWPFRun run = runs.get(i);
                String runText = run.toString().trim();
                if (!runText.equals("") && (runText.indexOf("${") != -1 || runText.equals("}"))) {
                    if ('$' == runText.charAt(0) && '{' == runText.charAt(1)) {
                        start = i;
                        runsIndex += i + ",";
                    }
                    if ((start != -1)) {
                        str += runText;
                    }
                    if ('}' == runText.charAt(runText.length() - 1)) {
                        if (start != -1) {
                            end = i;

                            for (int k = start; k <= end; k++) {
                                para.removeRun(k);
                                k--;
                                end--;
                            }
                        }
                    }
                }

            }

//			for (int i = start; i <= end; i++) {
//				para.removeRun(i);
//				i--;
//				end--;
//			}
            int doInt = 0;
            String[] runsIns = runsIndex.split(",");
            for (int k = 0; k < runsIns.length; k++) {
                if (!"".equals(str)) {
                    for (Map.Entry<String, Object> entry : params.entrySet()) {
                        String key = entry.getKey();
                        if (str.indexOf(key) != -1) {

                            Object value = entry.getValue();
                            if (value instanceof String) {
                                str = str.replace(key, value.toString());
                                if (((String) str).indexOf("\r") > 0) {
                                    // 设置换行
                                    String[] text = str.toString().split("\r");
                                    para.removeRun(0);
                                    for (int f = 0; f < text.length; f++) {
                                        if (f == 0) {
                                            // 此处不缩进因为word模板已经缩进了。
                                            para.createRun().setText(text[f].trim());
                                        } else {
                                            para.createRun().addCarriageReturn();// 硬回车
                                            // 注意：wps换行首行缩进是三个空格符，office要的话可以用
                                            // run.addTab();缩进或者四个空格符
                                            para.createRun().setText(text[f]);
                                        }
                                    }
                                } else {
//								para.createRun().setText((String) value);
                                    int num = 0;
                                    if (doInt == 0) {
                                        num = Integer.valueOf(runsIns[k]);
                                    } else {
                                        num = Integer.valueOf(runsIns[k]) + doInt;
                                    }
                                    para.insertNewRun(num).setText((String) value);
                                    doInt++;
                                }
                                // para.createRun().setText(str, 0);
                                break;
                            } else if (value instanceof Map) {
                                str = str.replace(key, "");
                                Map pic = (Map) value;
                                int width = Integer.parseInt(pic.get("width").toString());
                                int height = Integer.parseInt(pic.get("height").toString());
                                int picType = getPictureType(pic.get("type").toString());
                                byte[] byteArray = (byte[]) pic.get("content");


                                BufferedImage bufferImg = null;//图片
                                ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
                                //将图片读到BufferedImage
                                bufferImg = ImageIO.read(new File(""));
                                // 将图片写入流中
                                ImageIO.write(bufferImg, "png", byteArrayOut);

                                ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
                                try {
                                    // int ind =
                                    // doc.addPicture(byteInputStream,picType);
                                    // doc.createPicture(ind, width , height,para);
                                    doc.addPictureData(byteInputStream, picType);

                                    //创建一个word图片，并插入到文档中-->像素可改
                                    //doc.createPicture(doc.getAllPictures().size() - 1, 240, 240,paragraph);

                                    para.createRun().setText(str, 0);
                                    break;
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }

        }
    }

    /**
     * 为表格插入数据，行数不够添加新行
     *
     * @param table     需要插入数据的表格
     * @param tableList 插入数据集合
     */
    private static void insertTable(XWPFTable table, List<String[]> tableList) {
        // 创建行,根据需要插入的数据添加新行，不处理表头
        for (int i = 0; i < tableList.size(); i++) {
            XWPFTableRow row = table.createRow();
        }
        // 遍历表格插入数据
        List<XWPFTableRow> rows = table.getRows();
        int length = table.getRows().size();
        for (int i = 1; i < length - 1; i++) {
            XWPFTableRow newRow = table.getRow(i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            for (int j = 0; j < cells.size(); j++) {
                XWPFTableCell cell = cells.get(j);
                String s = tableList.get(i - 1)[j];
                cell.setText(s);
            }
        }
    }

    /**
     * 替换表格里面的变量
     *
     * @param doc    要替换的文档
     * @param params 参数
     */
    private void replaceInTable(CustomXWPFDocument doc, Map<String, Object> params, List<String[]> tableList) throws IOException {
        Iterator<XWPFTable> iterator = doc.getTablesIterator();
        XWPFTable table;
        List<XWPFTableRow> rows;
        List<XWPFTableCell> cells;
        List<XWPFParagraph> paras;
        while (iterator.hasNext()) {
            table = iterator.next();
//			System.out.println("------------>" + table.getRows().size());
            if (table.getRows().size() > 1) {
                // 判断表格是需要替换还是需要插入，判断逻辑有$为替换，表格无$为插入
                if (this.matcher(table.getText()).find()) {
                    rows = table.getRows();
                    for (XWPFTableRow row : rows) {
                        cells = row.getTableCells();
                        for (XWPFTableCell cell : cells) {
                            paras = cell.getParagraphs();
                            for (XWPFParagraph para : paras) {
                                this.replaceInPara(para, params, doc);
                            }
                        }
                    }
                } else {
                    insertTable(table, tableList); // 插入数据
                }
            }
        }
    }

    /**
     * 正则匹配字符串
     *
     * @param str
     * @return
     */
    private Matcher matcher(String str) {
        System.out.println(str);
        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str);
        return matcher;
    }

    /**
     * 根据图片类型，取得对应的图片类型代码
     *
     * @param picType
     * @return int
     */
    private static int getPictureType(String picType) {
        int res = CustomXWPFDocument.PICTURE_TYPE_PICT;
        if (picType != null) {
            if (picType.equalsIgnoreCase("png")) {
                res = CustomXWPFDocument.PICTURE_TYPE_PNG;
            } else if (picType.equalsIgnoreCase("dib")) {
                res = CustomXWPFDocument.PICTURE_TYPE_DIB;
            } else if (picType.equalsIgnoreCase("emf")) {
                res = CustomXWPFDocument.PICTURE_TYPE_EMF;
            } else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {
                res = CustomXWPFDocument.PICTURE_TYPE_JPEG;
            } else if (picType.equalsIgnoreCase("wmf")) {
                res = CustomXWPFDocument.PICTURE_TYPE_WMF;
            }
        }
        return res;
    }

    /**
     * 将输入流中的数据写入字节数组
     *
     * @param in
     * @return
     */
    public static byte[] inputStream2ByteArray(InputStream in, boolean isClose) {
        byte[] byteArray = null;
        try {
            int total = in.available();
            byteArray = new byte[total];
            in.read(byteArray);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (isClose) {
                try {
                    in.close();
                } catch (Exception e2) {
                    e2.getStackTrace();
                }
            }
        }
        return byteArray;
    }

    /**
     * 关闭输入流
     *
     * @param is
     */
    public void close(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭输出流
     *
     * @param os
     */
    public void close(OutputStream os) {
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}